package sys;

import com.alibaba.fastjson.JSON;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.symbolsolver.utils.SymbolSolverCollectionStrategy;
import com.github.javaparser.utils.ProjectRoot;
import com.github.javaparser.utils.SourceRoot;
import lombok.Data;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * @description:
 * @author: huangzhengri
 * @time: 2023-05-23 17:04
 */
public class JavaFileParser {

    Path path = Paths.get("D:\\aisino_project\\master\\invoice-service-master");
    @Test
    public void testParseProject2(){
        final ProjectRoot projectRoot =  new SymbolSolverCollectionStrategy().collect(path);
        System.out.println(projectRoot);
    }

    @Test
    public void testParseProject() throws IOException {
        SourceRoot sourceRoot = new SourceRoot(Paths.get("D:\\aisino_project\\master\\invoice-service-master"));
        ParserConfiguration parserConfiguration = new ParserConfiguration();
        parserConfiguration.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8);
        sourceRoot.setParserConfiguration(parserConfiguration);
        final List<ParseResult<CompilationUnit>> parseResults = sourceRoot.tryToParse("invoice-application-platform.src.main.java.cn.hnhtxx");
        System.out.println(parseResults);
    }

    @Test
    public void test1() throws FileNotFoundException {
        File file = new File("D:\\aisino_project\\master\\invoice-service-master\\invoice-application-platform\\src\\main\\java\\cn\\hnhtxx\\modules\\apiForward\\service\\impl\\ApiForwardServiceImpl.java");
        CompilationUnit compilationUnit = null;
        try {
            compilationUnit =  StaticJavaParser.parse(file);

            final List<VariableDeclarator> compilationUnitAll = compilationUnit.findAll(VariableDeclarator.class);
            for (VariableDeclarator variableDeclarator : compilationUnitAll) {
                final Type type = variableDeclarator.getType();
                System.out.println(type);
            }
            System.out.println();
        }catch (AssertionError error){
            System.out.println(file+" 解析失败");
        }
    }

    public static void main(String[] args) throws IOException {
        File file = new File("D:\\aisino_project\\master\\invoice-service-master\\invoice-application-platform\\src\\main\\java\\cn\\hnhtxx\\modules\\apiForward\\service\\ApiForwardService.java");
        File dir = new File("D:\\aisino_project\\master\\invoice-service-master");

        // 持久化
        final File storage = new File("D:\\aisino_project\\classTree_"+file.getName()+".txt");

        Dependency startDependency = null;
        if (!storage.exists()) {
            startDependency = new Dependency(file);
            dependencies(startDependency, dir, "cn.hnhtxx");
            FileUtils.writeStringToFile(storage, JSON.toJSONString(startDependency), StandardCharsets.UTF_8);
        }else {
            startDependency = JSON.parseObject(FileUtils.readFileToString(storage,StandardCharsets.UTF_8),Dependency.class);
        }

        checkFileIsNew(startDependency);

        printTree(startDependency, 0);
    }

    public static void checkFileIsNew(Dependency startDependency){
        final File findDir = new File("D:\\aisino_project\\invoice-manage");
        final Collection<File> files = FileUtils.listFiles(findDir, new String[]{"java"}, true);
        Map<String,File> fileMap = new HashMap<>();
        for (File file : files) {
            fileMap.put(file.getName(), file);
        }
        markDependencyIsNew(fileMap, startDependency);
    }

    public static void markDependencyIsNew(Map<String,File> fileMap, Dependency dependency){
        final boolean containsKey = fileMap.containsKey(dependency.getSource().getName());
        if (!containsKey){
            dependency.setNewFile(true);
        }
        for (Dependency dependencyDependency : dependency.getDependencies()) {
            markDependencyIsNew(fileMap,dependencyDependency);
        }
    }

    public static void printTree(Dependency dependency, int deep){
        for (int i = 0; i < deep; i++) {
            System.out.print("\t");
        }

        System.out.println(wholeClassName(dependency.getSource()) + " " + (dependency.isNewFile() ? "add " : "modify "));
        final List<Dependency> dependencies = dependency.getDependencies();
        for (Dependency child : dependencies) {
            printTree(child,deep + 1);
        }
    }

    private static String wholeClassName(File file){
        final int i = file.getPath().lastIndexOf("\\src\\main\\java");
        final String substring = file.getPath().substring(i + 15);
        final String classWholeName = StringUtils.replace(substring, "\\", ".");
        final String wholeClassName = classWholeName.substring(0, classWholeName.length() - 5);
        return wholeClassName;
    }

    @Data
    public static final class Dependency{
        private File source;
        private boolean newFile;
        private List<Dependency> dependencies = new ArrayList<>();

        public Dependency() {
        }

        public Dependency(File source) {
            this.source = source;
        }
    }

    public void compare() throws IOException {
        final File findDir = new File("D:\\aisino_project\\invoice-manage");
        final Collection<File> files = FileUtils.listFiles(findDir, new String[]{"java"}, true);
        Map<String,File> fileMap = new HashMap<>();
        for (File file : files) {
            fileMap.put(file.getName(), file);
        }

        final File file = new File("D:\\aisino_project\\class.txt");
        final List<String> list = FileUtils.readLines(file, StandardCharsets.UTF_8);
        List<File> newFiles = new ArrayList<>();
        for (String path : list) {
            final File modifyFile = new File(path);
            final boolean containsKey = fileMap.containsKey(modifyFile.getName());
            if (containsKey){
                System.out.println("包含文件 : "+ modifyFile.getName());
            }else {
                System.out.println("新添加文件 : "+ modifyFile.getName());
                newFiles.add(modifyFile);
            }
        }

        Collections.sort(newFiles);
        for (File newFile : newFiles) {
            System.out.println(newFile.toPath().toString());
        }
    }

    /**
     * 分析文件依赖
     * @param startFile
     * @param dir
     * @param packagePrefix
     */
    public static void dependencies(Dependency startDependency, File dir, String packagePrefix) throws FileNotFoundException {

        // 找出所有的 java 文件, 找到其类
        final Collection<File> files = FileUtils.listFiles(dir, new String[]{"java"}, true);

        Map<String,File> fileMap = new HashMap<>();
        for (File file : files) {
            final int i = file.getPath().lastIndexOf("\\src\\main\\java");
            final String substring = file.getPath().substring(i + 15);
            final String classWholeName = StringUtils.replace(substring, "\\", ".");
//            System.out.println(classWholeName);
            fileMap.put(classWholeName.substring(0, classWholeName.length() - 5),file);
        }

        // 解析 startFile, 找到所有引入
        CompilationUnit compilationUnit = null;
        try {
            compilationUnit =  StaticJavaParser.parse(startDependency.getSource());
        }catch (AssertionError error){
            System.out.println(startDependency.getSource()+" 解析失败");
        }

        final NodeList<ImportDeclaration> imports = compilationUnit.getImports();
        for (ImportDeclaration anImport : imports) {
            final String classWholeName = anImport.getName().toString();
            if (!classWholeName.startsWith(packagePrefix)){
                continue;
            }

            final File file = fileMap.get(classWholeName);
            if (file == null){
                System.out.println("类: "+ classWholeName + " 没有找到");
                continue;
            }
            final Dependency dependency = new Dependency(file);
            startDependency.getDependencies().add(dependency);
            dependencies(dependency, dir, packagePrefix);
        }

//        // 查询同目录下文件依赖
//        final File[] siblingsFiles = startDependency.getSource().getParentFile().listFiles();
//        compilationUnit.get
    }
}
